package com.gobang.common.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;

/**
 * JWT工具类
 * 提供JWT token的生成、验证和解析功能
 * 
 * @author System
 * @since 1.0.0
 */
@Slf4j
@Component
public class JWTUtil {

    /**
     * JWT加密密钥
     */
    @Value("${jwt.secret:gobang_jwt_secret_key_for_authentication_and_authorization}")
    private String secret;

    /**
     * JWT过期时间（毫秒）
     */
    @Value("${jwt.expiration:3600000}")  // 默认1小时
    private Long expiration;

    /**
     * JWT发行者
     */
    @Value("${jwt.issuer:gobang}")
    private String issuer;

    /**
     * 获取签名密钥
     *
     * @return 签名密钥
     */
    private Key getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    /**
     * 生成JWT Token
     *
     * @param userId 用户ID
     * @param username 用户名
     * @return JWT Token
     */
    public String generateToken(Long userId, String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);

        try {
            String token = Jwts.builder()
                    .setSubject(userId.toString())
                    .claim("username", username)
                    .setIssuer(issuer)
                    .setIssuedAt(now)
                    .setExpiration(expiryDate)
                    .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                    .compact();

            log.debug("JWT Token生成成功，用户ID：{}，用户名：{}", userId, username);
            return token;
        } catch (Exception e) {
            log.error("JWT Token生成失败，用户ID：{}，错误：{}", userId, e.getMessage(), e);
            throw new RuntimeException("Token生成失败", e);
        }
    }

    /**
     * 从Token中获取用户ID
     *
     * @param token JWT Token
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        try {
            Claims claims = parseToken(token);
            Long userId = Long.parseLong(claims.getSubject());
            log.debug("从Token中获取用户ID成功：{}", userId);
            return userId;
        } catch (Exception e) {
            log.error("从Token中获取用户ID失败，错误：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 从Token中获取用户名
     *
     * @param token JWT Token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        try {
            Claims claims = parseToken(token);
            String username = claims.get("username", String.class);
            log.debug("从Token中获取用户名成功：{}", username);
            return username;
        } catch (Exception e) {
            log.error("从Token中获取用户名失败，错误：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取Token过期时间
     *
     * @param token JWT Token
     * @return 过期时间
     */
    public Date getExpirationFromToken(String token) {
        try {
            Claims claims = parseToken(token);
            return claims.getExpiration();
        } catch (Exception e) {
            log.error("获取Token过期时间失败，错误：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 验证Token是否有效
     *
     * @param token JWT Token
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            log.debug("Token验证成功");
            return true;
        } catch (ExpiredJwtException e) {
            log.warn("Token已过期：{}", e.getMessage());
            return false;
        } catch (UnsupportedJwtException e) {
            log.warn("Token格式不支持：{}", e.getMessage());
            return false;
        } catch (MalformedJwtException e) {
            log.warn("Token格式错误：{}", e.getMessage());
            return false;
        } catch (SignatureException e) {
            log.warn("Token签名验证失败：{}", e.getMessage());
            return false;
        } catch (IllegalArgumentException e) {
            log.warn("Token参数非法：{}", e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("Token验证失败，未知错误：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 检查Token是否即将过期
     *
     * @param token JWT Token
     * @param threshold 提前刷新时间阈值（毫秒）
     * @return 是否即将过期
     */
    public boolean isTokenExpiringSoon(String token, long threshold) {
        try {
            Date expiration = getExpirationFromToken(token);
            if (expiration == null) {
                return true;
            }
            
            long timeToExpire = expiration.getTime() - System.currentTimeMillis();
            return timeToExpire <= threshold;
        } catch (Exception e) {
            log.warn("检查Token过期时间失败：{}", e.getMessage());
            return true;
        }
    }

    /**
     * 刷新Token
     *
     * @param token 原Token
     * @return 新Token
     */
    public String refreshToken(String token) {
        try {
            Long userId = getUserIdFromToken(token);
            String username = getUsernameFromToken(token);
            
            if (userId != null && username != null) {
                return generateToken(userId, username);
            }
            
            log.warn("Token刷新失败，无法获取用户信息");
            return null;
        } catch (Exception e) {
            log.error("Token刷新失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析Token获取Claims
     *
     * @param token JWT Token
     * @return Claims对象
     */
    private Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 获取Token过期时间（秒）
     *
     * @return 过期时间（秒）
     */
    public Long getExpirationInSeconds() {
        return expiration / 1000;
    }
} 